package com.giraffe.aiochat.client;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;

import com.giraffe.aiochat.model.Message;
import com.giraffe.aiochat.model.MessageType;
import com.giraffe.aiochat.utils.MessageUtils;

public class AIOClient {
    private AsynchronousSocketChannel client;
    private final CountDownLatch latch = new CountDownLatch(1); // 用于保持客户端运行
    private String nickname; // 用户昵称

    public void start() throws IOException, InterruptedException {
        // 获取用户昵称
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入您的昵称: ");
        nickname = scanner.nextLine().trim();
        while (nickname.isEmpty()) {
            System.out.print("昵称不能为空，请重新输入: ");
            nickname = scanner.nextLine().trim();
        }

        client = AsynchronousSocketChannel.open();

        // 异步连接服务器
        client.connect(new InetSocketAddress("localhost", 8080), null, new CompletionHandler<Void, Void>() {
            @Override
            public void completed(Void result, Void attachment) {
                System.out.println("已连接到服务器");
                startReading(); // 启动消息接收循环
                startWriting(); // 启动消息发送
            }

            @Override
            public void failed(Throwable exc, Void attachment) {
                System.err.println("连接失败: " + exc.getMessage());
                latch.countDown();
            }
        });

        latch.await(); // 阻塞主线程，防止提前退出
    }

    // 异步接收服务器消息
    private void startReading() {
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        client.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
            @Override
            public void completed(Integer bytesRead, ByteBuffer buffer) {
                if (bytesRead > 0) {
                    buffer.flip();
                    String jsonStr = new String(buffer.array(), 0, bytesRead);
                    Message message = MessageUtils.fromJson(jsonStr);
                    String displayMessage = message.getNickname() + ": " + message.getContent();
                    System.out.println(displayMessage);
                    buffer.clear();
                    client.read(buffer, buffer, this); // 继续监听下一条消息
                }
            }

            @Override
            public void failed(Throwable exc, ByteBuffer buffer) {
                System.err.println("读取失败: " + exc.getMessage());
                close();
            }
        });
    }

    // 发送用户输入的消息
    private void startWriting() {
        new Thread(() -> {
            Scanner scanner = new Scanner(System.in);
            while (client.isOpen()) {
                System.out.print("请输入消息: ");
                String content = scanner.nextLine();
                // 创建消息对象
                Message message = new Message(MessageType.CHAT, nickname, content);
                String jsonStr = MessageUtils.toJson(message);
                ByteBuffer buffer = ByteBuffer.wrap(jsonStr.getBytes());
                client.write(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
                    @Override
                    public void completed(Integer bytesWritten, ByteBuffer buffer) {
                        if (!buffer.hasRemaining()) {
                            System.out.println("消息已发送");
                        } else {
                            client.write(buffer, buffer, this); // 继续发送剩余数据
                        }
                    }

                    @Override
                    public void failed(Throwable exc, ByteBuffer buffer) {
                        System.err.println("发送失败: " + exc.getMessage());
                        close();
                    }
                });
            }
            scanner.close();
        }).start();
    }

    private void close() {
        try {
            if (client != null && client.isOpen()) {
                client.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            latch.countDown();
        }
    }

    public static void main(String[] args) {
        try {
            new AIOClient().start();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}
